package cn.francis.common.config;

import cn.francis.common.constant.AsyncConfigurationConstants;
import lombok.extern.slf4j.Slf4j;
import org.springframework.aop.interceptor.AsyncUncaughtExceptionHandler;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.AsyncConfigurer;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;

import java.util.concurrent.Executor;
import java.util.concurrent.ThreadPoolExecutor;

/**
 * @author 张俊辉
 */

@Slf4j
@EnableAsync
@Configuration
public class AsyncConfiguration implements AsyncConfigurer {

    /**
     * 定义并注册名为 "asyncPoolTaskExecutor" 的线程池执行器 Bean，用于处理 @Async 异步任务。
     * <p>
     * 该线程池通过 ThreadPoolTaskExecutor 实现，支持线程池参数自定义配置，适用于并发控制和资源管理。
     * 配置项从 AsyncConfigurationConstants 常量类中读取，便于集中维护与调整。
     * <p>
     * 参数说明：
     * <ul>
     *   <li>corePoolSize：核心线程数，始终保留在线的线程数量</li>
     *   <li>maxPoolSize：最大线程数，当队列满时，允许的最大线程数</li>
     *   <li>queueCapacity：任务队列容量，超过核心线程但未超过队列容量的任务会被缓存</li>
     *   <li>keepAliveSeconds：非核心线程的空闲存活时间</li>
     *   <li>threadNamePrefix：线程名前缀，便于排查问题时识别异步线程</li>
     *   <li>waitForTasksToCompleteOnShutdown：应用关闭时是否等待任务执行完成</li>
     *   <li>rejectedExecutionHandler：拒绝策略，此处使用 CallerRunsPolicy 表示由调用线程执行任务</li>
     * </ul>
     *
     * @return ThreadPoolTaskExecutor 异步线程池执行器
     */
    @Bean(name = "asyncPoolTaskExecutor")
    public ThreadPoolTaskExecutor executor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(AsyncConfigurationConstants.CORE_SIZE);
        executor.setMaxPoolSize(AsyncConfigurationConstants.MAX_CORE_SIZE);
        executor.setQueueCapacity(AsyncConfigurationConstants.QUEUE_CAPACITY_SIZE);
        executor.setKeepAliveSeconds(AsyncConfigurationConstants.KEEP_ALIVE_TIME);
        executor.setThreadNamePrefix(AsyncConfigurationConstants.THREAD_NAME_PREFIX);
        executor.setWaitForTasksToCompleteOnShutdown(Boolean.TRUE);
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        executor.initialize();
        return executor;
    }

    /**
     * 返回用于执行异步任务的线程池执行器（Executor）。
     * <p>
     * 当项目中使用 @Async 注解标注异步方法时，Spring 将通过该方法返回的线程池执行器来执行这些异步任务。
     * 若未自定义该方法，则 Spring 使用默认的 SimpleAsyncTaskExecutor，可能导致线程资源不可控。
     * <p>
     * 推荐配合 ThreadPoolTaskExecutor 自定义线程池参数，如核心线程数、队列容量、线程名称前缀等，以更好地管理并发任务。
     *
     * @return Executor 异步任务执行器
     */
    @Override
    public Executor getAsyncExecutor() {
        return executor();
    }

    /**
     * 提供自定义的异步未捕获异常处理器。
     * <p>
     * 当使用 @Async 注解的方法为 void 返回类型且在执行过程中抛出异常时，
     * 异常将无法通过 Future 机制捕获，因此需要通过该方法提供统一的异常处理逻辑。
     * <p>
     * 本实现中记录了异常信息和发生异常的方法名称，方便排查问题。
     *
     * @return AsyncUncaughtExceptionHandler 异步未捕获异常处理器
     */
    @Override
    public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
        return (ex, method, params) -> log.error("线程池执行任务发送未知错误, 执行方法：{}", method.getName(), ex);
    }
}
